#pragma once

#include <iostream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <fstream>
#include "Log.hpp"
#include "Comm.hpp"
const std::string Sep = "\r\n";
const std::string Blank = " ";
const std::string BlankLine = Sep;
const std::string HeaderLineSep = ": ";
const std::string defaulthomepage = "wwwroot";
const std::string defaultpath = "index.html";
const std::string page404 = "wwwroot/404.html";
const std::string defaultversion = "HTTP/1.1";

using namespace LogModule;
class HttpRequest
{
	// GET / HTTP/1.1
	// Host: 14.103.241.129:8086
	// Connection: keep-alive
	// Upgrade-Insecure-Requests: 1
	// User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0
	// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
	// Accept-Encoding: gzip, deflate
	// Accept-Language: zh-CN,zh;q=0.9
private:
	// 分割请求行
	void Onesegmentation(std::string &resquest_in)
	{
		std::stringstream ss(resquest_in);
		ss >> _method >> _url >> _version;
	}
	// 处理key-value对
	bool Parsehandkv()
	{
		std::string key, value;
		for (auto &head : _req_header)
		{
			if (ParseString(head, HeaderLineSep, &key, &value))
			{
				_headkv[key] = value;
			}
			else
			{
				return false; // 解析失败
			}
		}
		return true;
	}
	// 处理报文
	bool ParseMessage(std::string &resquest_in)
	{
		std::string line;
		while (true)
		{
			bool r = ParseOneLine(resquest_in, &line, Sep);
			if (r && !line.empty()) // 成功返回并且读到的行不为空
			{
				_req_header.push_back(line);
			}
			else if (r && line.empty()) // 成功返回并且读到的行为空，说明读到空行，结束解析报文
			{
				_blank_line = Sep; // 保存空行
				break;
			}
			else // 失败返回
			{
				return false;
			}
		}
		// 把报文分成key-value对
		if (!Parsehandkv())
		{
			return false;
		}
		return true;
	}

public:
	HttpRequest() {}
	~HttpRequest() {}
	bool IsHasArgs()
	{
		return _isexec;
	}
	std::string Path() {return _path;}
	std::string Args() {return _args;}

	// 反序列化
	void Deserialize(std::string &resquest_in)
	{
		// 解析请求行
		if (ParseOneLine(resquest_in, &_req_line, Sep))
		{
			// 分割请求行
			Onesegmentation(_req_line);
			// 处理报文
			ParseMessage(resquest_in);
			// 处理数据内容
			_body = resquest_in; // 最后剩下的就是数据内容
			
			// 分析请求中，是否含有参数..
            if (_method == "POST")
            {
                _isexec = true; // 参数在正文
                _args = _body;
				_path = _url;
            }
            else if (_method == "GET")
            {
                auto pos = _url.find("?");
                if (pos != std::string::npos)
                {
                    _isexec = true;
                    // /login?name=zhang&passwd=123456
                    _path = _url.substr(0, pos);
                    _args = _url.substr(pos + 1);

			std::cout << _path << std::endl;
			std::cout << _args << std::endl;
			std::cout <<"11111111111111111111111111111111111111111111111111"<<std::endl;
                }
            }
		}
	}
	// 获得url中的内容
	std::string UrlContent(const std::string path)
	{
		// 读取二进制
		std::string content;
		std::ifstream file(path, std::ios::binary);
		if (!file.is_open())
		{
			return std::string();
		}
		file.seekg(0, file.end);
		int length = file.tellg();
		file.seekg(0, file.beg);

		content.resize(length);
		file.read((char *)content.c_str(), length);
		file.close();

		// 读取的文件为字符串时
		// std::string content;
		// // 打开文件
		// std::ifstream file(_url);
		// if (!file.is_open())
		// {
		// 	return std::string();
		// }
		// std::string line;
		// // 读取文件内容
		// while (std::getline(file, line))
		// {
		// 	content += line;
		// }
		// file.close();
		return content;
	}
	void Print()
	{
		std::cout << "_method: " << _method << std::endl;
		std::cout << "_uri: " << _url << std::endl;
		std::cout << "_version: " << _version << std::endl;

		for (auto &kv : _headkv)
		{
			std::cout << kv.first << " # " << kv.second << std::endl;
		}
		std::cout << "_blank_line: " << _blank_line << std::endl;
		std::cout << "_body: " << _body << std::endl;
	}
	std::string Url()
	{
		return _url;
	}
	void newUrl(const std::string &newurl)
	{
		_url = newurl;
	}
	std::string Suffix()
	{
		// 获取文件后缀
		auto pos = _url.rfind('.');
		if (pos == std::string::npos)
		{
			return std::string();
		}
		return _url.substr(pos + 1);
	}

private:
	std::string _req_line;				  // GET / HTTP/1.1
	std::vector<std::string> _req_header; // Host: 14.103.241.129:8086\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate\r\nAccept-
	std::string _blank_line;			  // \r\n
	std::string _body;					  // 数据内容

	std::string _method;								  // GET
	std::string _url;									  // /
	std::string _version;								  // HTTP/1.1
	std::unordered_map<std::string, std::string> _headkv; // 处理后的key-value对
	bool _isexec = false;								  // 是否执行
	std::string _path;									  // 请求路径
	std::string _args;									  // 请求参数
};

class HttpResponse
{
public:
	HttpResponse() : _verion(defaultversion)
	{
	}
	~HttpResponse()
	{
	}
	// 构建
	void build(HttpRequest &req_str)
	{

		// 把默认打开页面路径添加到url
		std::string url = defaulthomepage + req_str.Url();
		if (url.back() == '/')
		{
			url += defaultpath;
			req_str.newUrl(url);
			LOG(LogLevel::DEBUG) << "url: " << url;
		}
		// 获取文件内容
		content = req_str.UrlContent(url);
		LOG(LogLevel::DEBUG) << "content length: " << content.size();
		LOG(LogLevel::DEBUG) << "------客户端在请求: " << req_str.Url();
		req_str.Print();
		LOG(LogLevel::DEBUG) << "----------------------------";
		if (content.empty())
		{
			_status_code = 404;
			req_str.newUrl(page404);
			content = req_str.UrlContent(page404); // 再次获取内容
		}
		else
		{
			// 说明文件存在
			_status_code = 200;
		}
		_status_msg = codetype(_status_code); // 根据状态码获取状态信息
		// Content-Length 文件内容长度
		if (!content.empty())
		{
			int content_length = content.size();
			Sethead("Content-Length", std::to_string(content_length));
		}
		// 根据文件后缀来判断文件类型
		std::string suffix = req_str.Suffix();
		std::string file_type = codesuffix(suffix);
		Sethead("Content-Type", file_type);

		for (auto &kv : _headkv)
		{
			LOG(LogLevel::DEBUG) << kv.first << " # " << kv.second;
			_req_header.push_back(kv.first + HeaderLineSep + kv.second);
		}
	}

	// 序列化
	void serialize(std::string *resquest_out)
	{
		// 构建响应行
		_req_line = _verion + Blank + std::to_string(_status_code) + Blank + _status_msg + Sep;

		// 空行
		_blank_line = BlankLine;

		// 填写内容
		_body = content;

		*resquest_out = _req_line;
		for (auto &head : _req_header)
		{
			*resquest_out += (head + Sep);
		}
		*resquest_out += _blank_line;
		*resquest_out += _body;
	}

private:
	std::string codetype(int code)
	{
		switch (code)
		{
		case 200:
			return "OK";
		case 404:
			return "Not Found";
		default:
			return "Unknown";
		}
	}
	std::string codesuffix(const std::string &suffix)
	{
		if (suffix == "html")
		{
			return "text/html";
		}
		else if (suffix == "jpg" || suffix == "jpeg")
		{
			return "image/jpeg";
		}
		else
		{
			return "text/plain";
		}
	}
	void Sethead(std::string key, std::string value)
	{
		_headkv[key] = value;
	}

private:
	std::string content; // 文件内容
	std::string _verion;
	int _status_code;									  // 状态码
	std::string _status_msg;							  // 状态信息
	std::unordered_map<std::string, std::string> _headkv; // 处理key-value对

	// 最终要这4部分，构建应答
	std::string _req_line;				  // GET / HTTP/1.1
	std::vector<std::string> _req_header; // Host: 14.103.241.129:8086\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate\r\nAccept-
	std::string _blank_line;			  // \r\n
	std::string _body;					  // 数据内容
};